use std::collections::HashMap;

use derive_builder::Builder;
use serde::{Deserialize, Serialize};

use crate::error::Error;
use crate::modeling::Value;

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "QueryOptionsBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct QueryOptions {}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "ExecuteOptionsBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct ExecuteOptions {
    pub options: HashMap<String, String>,
}

impl ExecuteOptions {
    pub fn new() -> Self {
        Self {
            options: HashMap::new(),
        }
    }
}

#[async_trait::async_trait]
pub trait Connector {
    async fn query(
        &self,
        sql: &String,
        args: &Vec<Value>,
        options: QueryOptions,
    ) -> anyhow::Result<(Vec<Value>, Vec<Value>)>;

    async fn query_one(
        &self,
        sql: &String,
        args: &Vec<Value>,
        options: QueryOptions,
    ) -> anyhow::Result<(Vec<Value>, Value)>;

    async fn query_map(
        &self,
        sql: &String,
        args: &Vec<Value>,
        options: QueryOptions,
    ) -> anyhow::Result<HashMap<String, Value>>;

    async fn query_maps(
        &self,
        sql: &String,
        args: &Vec<Value>,
        options: QueryOptions,
    ) -> anyhow::Result<Vec<HashMap<String, Value>>>;

    async fn execute(
        &self,
        sql: &String,
        args: &Vec<Value>,
        options: ExecuteOptions,
    ) -> anyhow::Result<i64>;

    async fn close(&mut self) -> anyhow::Result<i32>;

    async fn query_one_value(
        &self,
        sql: &String,
        args: &Vec<Value>,
        options: QueryOptions,
    ) -> anyhow::Result<Value> {
        if let (_, Value::Array(mut v)) = self.query_one(sql, args, options).await? {
            if v.len() > 0 {
                return v.pop().map_or(Err(anyhow::anyhow!("查询失败")), |v| Ok(v));
            }
        }
        Err(anyhow::anyhow!("查询失败"))
    }

    async fn query_object(
        &self,
        sql: &String,
        args: &Vec<Value>,
        options: QueryOptions,
    ) -> anyhow::Result<Value> {
        let map = self.query_map(sql, args, options).await?;
        Ok(Value::Object(map))
    }

    async fn query_objects(
        &self,
        sql: &String,
        args: &Vec<Value>,
        options: QueryOptions,
    ) -> anyhow::Result<Vec<Value>> {
        let maps = self.query_maps(sql, args, options).await?;

        Ok(maps.iter().map(|v| Value::Object(v.clone())).collect())
    }
}
